package editor.widgets;

import observer.ObservedString;
import observer.StringObserver;

import javax.swing.*;
import javax.swing.event.AncestorListener;
import javax.swing.event.AncestorEvent;
import java.awt.*;

/**
 * This is a {@link javax.swing.JComboBox} that automatically updates the {@link ObservedString} that it manages,
 * so that the model is updated properly.
 *
 * FIXME: This doesn't support being updated from outside the widget (e.g. undos) like {@link ObservedStringField} does.
 *
 * @author Neil Dickson
 */
public class ObservedStringComboBox extends JComboBox implements StringObserver, AncestorListener {
	private ObservedString value;

	public ObservedStringComboBox(ObservedString value,String[] possibleValues) {
		super();
		for (String s : possibleValues) {
			addItem(s);
		}
		this.value = value;
		setSelectedItem(value.toString(),false);
		value.addObserver(this);
		addAncestorListener(this);
	}

	public void valueChanged(ObservedString s, String oldValue) {
		setSelectedItem(s.toString(),false);
	}

	public void setSelectedItem(String s,boolean updateValue) {
		super.setSelectedItem(s);
		if (getSelectedItem().equals(s) && updateValue) {
			value.setValue(this,s);
		}
	}

	public void setSelectedItem(Object s) {
		if (s instanceof String) {
			setSelectedItem((String)s,true);
		}
		else if (s instanceof ObservedString) {
			setSelectedItem(s.toString(),true);
		}
		else {
			throw new ClassCastException("ObservedIntComboBox doesn't contain items of class "+s.getClass().getName());
		}
	}

	public void setSelectedIndex(int index) {
		super.setSelectedIndex(index);
		value.setValue(this,((String)getItemAt(index)));
	}

	public void setBackground(Color bg) {
		super.setBackground(bg);
		setOpaque(bg.getAlpha()==255);
	}

	public void setPossibleValues(String[] possibleValues) {
		int index = getSelectedIndex();
		removeAllItems();
		for (String s : possibleValues) {
			addItem(s);
		}
		setSelectedIndex(Math.min(index,possibleValues.length-1));
	}

	public void ancestorAdded(AncestorEvent event) {
		value.addObserver(this);
	}

	public void ancestorRemoved(AncestorEvent event) {
		value.removeObserver(this);
	}

	public void ancestorMoved(AncestorEvent event) {}

	/**
	 * Paints this combo box, but first checks for a bug in Java's implementation of JComboBox on Windows
	 * @param g
	 */
	protected void paintComponent(Graphics g) {
		if (getWidth()>=0x4000 || getHeight()>=0x4000) {
			System.err.println("JComboBox bug occurred with size: "+getSize());
			FontMetrics font = getFontMetrics(getFont());
			Dimension dim = new Dimension(24,24);
			for (int i=0; i<getItemCount(); ++i) {
				dim.width = Math.max(dim.width,20+font.stringWidth(getItemAt(i).toString()));
			}
			System.err.println("Setting it to size: "+dim);
			setMinimumSize(dim);
			setPreferredSize(dim);
			setMaximumSize(dim);
			setSize(dim);
		}
		super.paintComponent(g);
	}
}
